package com.gaga.common.utils;

import cn.hutool.core.thread.ThreadUtil;
import com.gaga.common.enums.PlayerType;
import com.gaga.common.utils.audio.AudioVolumeController;
import org.jtransforms.fft.FloatFFT_1D;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;

/**
 * @author liujia
 * @version 1.0
 * @date 2025/3/30-15:32
 */
public class AudioPlayerUtils2Bak implements LineListener {

    private SourceDataLine line;
    private AudioInputStream stream;
    // 新增速度系数
    private volatile float speedFactor = 1.0f;
    private volatile boolean isPlaying = false;

    //初始增益为0dB
    private float[] eqGains = new float[]{1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};

    private float sampleRate;


    private AudioVolumeController volumeController = new AudioVolumeController();

    /**
     * 播放完成回调方法
     */
    private Runnable onPlaybackFinished;

    /**
     * 添加完成回调方法
     */
    public void setOnPlaybackFinished(Runnable callback) {
        this.onPlaybackFinished = callback;
    }

    /**
     * 初始化音频设备（兼容变速）
     *
     * @param filePath
     * @param deviceName
     */
    public void init(String filePath, String deviceName) {
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return;
            }

            // 获取原始音频流并转换为PCM格式
            AudioInputStream originalStream = AudioSystem.getAudioInputStream(file);
            AudioFormat baseFormat = originalStream.getFormat();
            System.out.println(baseFormat.getSampleRate());
            AudioFormat decodedFormat = new AudioFormat(
                    AudioFormat.Encoding.PCM_SIGNED,
                    baseFormat.getSampleRate(),
                    16,
                    baseFormat.getChannels(),
                    baseFormat.getChannels() * 2,
                    baseFormat.getSampleRate(),
                    false
            );
            this.stream = AudioSystem.getAudioInputStream(decodedFormat, originalStream);
            this.sampleRate = decodedFormat.getSampleRate();
            // 获取指定音频设备
            Mixer.Info mixerInfo = DeviceInfoUtils.getTargetAudioDevice(deviceName, true);
            Mixer mixer = AudioSystem.getMixer(mixerInfo);

            line = (SourceDataLine) mixer.getLine(new DataLine.Info(SourceDataLine.class, decodedFormat));
            line.open(decodedFormat);
            volumeController.initVolumeControl(line);
            line.addLineListener(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setSpeed(float factor) {
        this.speedFactor = Math.max(0.5f, Math.min(2.0f, factor));
    }

    public void setEqBandGain(int band, float gainDb) {
        gainDb = Math.max(-12.0f, Math.min(12.0f, gainDb));
        if (Math.abs(gainDb) > 12.0f) {
            System.out.println("警告：增益超过±12dB可能产生失真");
        }
        eqGains[band] = (float) Math.pow(10, gainDb / 20.0);

    }


    // 重构播放逻辑
    public void play() {
        if (line != null && !isPlaying) {
            ThreadUtil.execute(() -> {
                try {
                    isPlaying = true;
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    line.start();
                    AudioFormat format = line.getFormat();
                    boolean isBigEndian = format.isBigEndian();
                    int frameSize = format.getFrameSize();

                    while (isPlaying && (bytesRead = stream.read(buffer)) != -1) {
                        // 转换为short数组处理
                        short[] samples = bytesToShorts(buffer, bytesRead, isBigEndian);
                        // 应用重采样
                        short[] resampled = resample(samples, speedFactor);
                        short[] equalized = applyEqualizer(resampled);
                        // 转换回字节数组
                        byte[] processed = shortsToBytes(resampled, isBigEndian);
                        // 确保写入的字节数是帧大小的整数倍
                        int adjustedLength = processed.length - (processed.length % frameSize);

                        line.write(processed, 0, adjustedLength);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    stop();
                }
            });
        }
    }

    private short[] resample(short[] original, float speedFactor) {
        int newLength = (int) (original.length / speedFactor);
        short[] resampled = new short[newLength];
        for (int i = 0; i < newLength; i++) {
            float pos = i * speedFactor;
            int posInt = (int) pos;
            float frac = pos - posInt;
            if (posInt >= original.length - 1) {
                resampled[i] = original[original.length - 1];
            } else if (posInt < 0) {
                resampled[i] = original[0];
            } else {
                short prev = original[posInt];
                short next = original[posInt + 1];
                resampled[i] = (short) (prev + (next - prev) * frac);
            }
        }
        return resampled;
    }


    private short[] bytesToShorts(byte[] bytes, int length, boolean isBigEndian) {
        short[] shorts = new short[length / 2];
        for (int i = 0; i < shorts.length; i++) {
            int hi = isBigEndian ? bytes[2 * i] : bytes[2 * i + 1];
            int lo = isBigEndian ? bytes[2 * i + 1] : bytes[2 * i];
            shorts[i] = (short) ((hi << 8) | (lo & 0xFF));
        }
        return shorts;
    }


    // 重构停止逻辑
    public void stop() {
        if (line != null) {
            line.drain();
            line.stop();
            try {
                stream.close();
            } catch (IOException e) { /* 异常处理 */ }
            line.close();   // 后关闭设备
            isPlaying = false;
            if (onPlaybackFinished != null) {
                // 触发回调
                onPlaybackFinished.run();
            }
        }
    }

    @Override
    public void update(LineEvent event) {
        if (event.getType() == LineEvent.Type.STOP) {
            // 仅在非用户主动暂停时触发停止
            System.out.println("播放自然结束");
        }
    }

    /**
     * 设置音量
     */
    public void setVolume(float volume) {
        volumeController.setVolume(volume);
    }

    private short[] applyEqualizer(short[] audioBytes) {
        // 1. 字节数组转短数组（16位PCM）

        // 2. 转换为浮点数组（-1.0f ~ 1.0f）
        float[] floatSamples = new float[audioBytes.length];
        for (int i = 0; i < audioBytes.length; i++) {
            floatSamples[i] = audioBytes[i] / 32768.0f;
        }

        // 3. 均衡器核心处理（频域处理）
        processEqualizerInFrequencyDomain(floatSamples);

        // 4. 浮点转短数组（截断/饱和处理）
        short[] outputShorts = new short[floatSamples.length];
        for (int i = 0; i < floatSamples.length; i++) {
            float val = floatSamples[i] * 32768.0f;
            outputShorts[i] = (short) Math.max(-32768, Math.min(32767, val));
        }
        // 5. 短数组转字节数组
        return outputShorts;
    }

    // 频域处理核心逻辑（提取为独立方法）
    private void processEqualizerInFrequencyDomain(float[] floatSamples) {


        // 检查是否需要处理
        boolean needProcess = false;
        for (float gain : eqGains) {
            if (gain != 1.0f) {
                needProcess = true;
                break;
            }
        }
        if (!needProcess) {
            return;
        }

        int fftSize = 1024;
        int overlap = fftSize / 2;
        FloatFFT_1D fft = new FloatFFT_1D(fftSize);
        float[] window = getHanningWindow(fftSize);

        float[] output = new float[floatSamples.length];
        Arrays.fill(output, 0.0f);
        for (int pos = 0; pos < floatSamples.length; pos += overlap) {
            // 分帧加窗
            float[] frame = new float[fftSize];
            System.arraycopy(floatSamples, pos, frame, 0, Math.min(fftSize, floatSamples.length - pos));

            // FFT
            float[] fftData = new float[fftSize * 2];
            System.arraycopy(frame, 0, fftData, 0, fftSize);
            fft.realForward(fftData);

            // 应用频段增益
            applyFrequencyGain(fftData, fftSize, sampleRate);

            // 逆FFT
            fft.realInverse(fftData, true);

            // 叠加到输出
            for (int i = 0; i < fftSize && pos + i < floatSamples.length; i++) {
                output[pos + i] += fftData[i] * window[i];
            }
        }

        // 添加重叠区域归一化
        int overlapTimes = fftSize / overlap;
        for (int i = 0; i < output.length; i++) {
            output[i] /= overlapTimes;
        }
        System.arraycopy(output, 0, floatSamples, 0, output.length);
    }

    // 辅助方法：字节转短数组（保留原逻辑）
    private short[] bytesToShorts(byte[] bytes, boolean isBigEndian) {
        short[] shorts = new short[bytes.length / 2];
        for (int i = 0; i < shorts.length; i++) {
            int hi = isBigEndian ? bytes[2 * i] : bytes[2 * i + 1];
            int lo = isBigEndian ? bytes[2 * i + 1] : bytes[2 * i];
            shorts[i] = (short) ((hi << 8) | (lo & 0xFF));
        }
        return shorts;
    }

    // 辅助方法：短数组转字节（保留原逻辑）
    private byte[] shortsToBytes(short[] shorts, boolean isBigEndian) {
        byte[] bytes = new byte[shorts.length * 2];
        for (int i = 0; i < shorts.length; i++) {
            if (isBigEndian) {
                bytes[2 * i] = (byte) (shorts[i] >> 8);
                bytes[2 * i + 1] = (byte) shorts[i];
            } else {
                bytes[2 * i + 1] = (byte) (shorts[i] >> 8);
                bytes[2 * i] = (byte) shorts[i];
            }
        }
        return bytes;
    }

    private float[] getHanningWindow(int size) {
        float[] window = new float[size];
        for (int i = 0; i < size; i++) {
            window[i] = 0.5f * (1.0f - (float) Math.cos(2 * Math.PI * i / (size - 1)));
        }
        return window;
    }


    private void applyFrequencyGain(float[] fftData, int fftSize, float sampleRate) {
        float binWidth = sampleRate / fftSize;
        float[] centerFreqs = {60, 150, 400, 1000, 2400, 6000, 12000};
        float[] bandwidths = {60, 150, 400, 1000, 2400, 6000, 12000};

        for (int band = 0; band < 7; band++) {
            float centerFreq = centerFreqs[band];
            float bandWidthHz = bandwidths[band];

            // 计算有效频段范围
            float lowFreq = centerFreq - bandWidthHz / 2;
            float highFreq = centerFreq + bandWidthHz / 2;

            int startBin = Math.max(1, (int) (lowFreq / binWidth));
            int endBin = Math.min(fftSize / 2 - 1, (int) (highFreq / binWidth));

            // 应用梯形增益
            for (int bin = startBin; bin <= endBin; bin++) {
                float freq = bin * binWidth;
                float attenuation = 1.0f - Math.abs(freq - centerFreq) / bandWidthHz;
                attenuation = Math.max(0, Math.min(1, attenuation));

                int idx = bin * 2;
                float actualGain = (1.0f - attenuation) + eqGains[band] * attenuation;
                // 应用增益（线性）
                fftData[idx] *= actualGain;
                fftData[idx + 1] *= actualGain;

                // 处理镜像频率
                int mirrorBin = fftSize - bin;
                fftData[mirrorBin * 2] = fftData[idx];
                fftData[mirrorBin * 2 + 1] = -fftData[idx + 1];
            }

            // 在增益应用后添加
            for (int bin = 1; bin < fftSize / 2; bin++) {
                int mirror = fftSize - bin;
                fftData[mirror * 2] = fftData[bin * 2];
                fftData[mirror * 2 + 1] = -fftData[bin * 2 + 1];
            }
        }


    }

    public static void main(String[] args) throws Exception {

        AudioPlayerUtils2 player = new AudioPlayerUtils2();
        player.init("C:/Users/lenovo/Desktop/test/1.wav", "耳机 (AirPro Stereo)", PlayerType.ANCHOR);
        // 播放 这个播放速度需要修改
        player.setSpeed(1f);
        player.setVolume(0.5f);
//        player.setEqBandGain(0, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(1, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(2, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(3, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(4, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(5, 12.0f); // 提升中频1kHz
//        player.setEqBandGain(6, 12.0f); // 提升中频1kHz
        player.play();
    }

}
